#include "MD5Signature.h"
#include "StlFile.h"
#include "Utils.h"
#include <exception>

namespace GPUCC
{
	std::vector<MD5Signature> MD5Signature::ParseSignaturesFile(const std::string& File)
	{
		std::vector<MD5Signature> Signatures;
		StlFile SignaturesFile(File);
		std::string CurrentLine;

		if (SignaturesFile.Open())
		{
			int NumberOfSignatures = 0;

			while (!SignaturesFile.GetStream().eof())
			{
				std::getline(SignaturesFile.GetStream(), CurrentLine);
				++NumberOfSignatures;
			}

			Signatures.reserve(NumberOfSignatures);
			
			SignaturesFile.Close();
			
			if (SignaturesFile.Open())
			{
				while (!SignaturesFile.GetStream().eof())
				{
					std::getline(SignaturesFile.GetStream(), CurrentLine);

					if (CurrentLine.compare("") != 0)
					{
						std::vector<std::string> Substrings = Utils::SplitString(CurrentLine, ':');

						if (Substrings.size() != 3)
						{
							throw std::exception("Invalid signature format!");
						}
						else
						{
							MD5 HashValue;

							ConvertBufferToMD5(Utils::ConvertHexToBytes(Substrings[0]), HashValue);

							Signatures.push_back(MD5Signature(Substrings[2], Utils::ConvertStringToUnsignedInt(Substrings[1]), HashValue));
						}
					}
				}
			}

			SignaturesFile.Close();
		}
		
		Signatures.shrink_to_fit();

		return (Signatures);
	}

	MD5Signature::MD5Signature()
	{
	}

	MD5Signature::MD5Signature(const std::string Name, const unsigned int Size, const MD5& Value) : m_Name(Name), m_Size(Size)
	{
		CopyMemory(this->m_Value.data(), Value, sizeof(MD5Signature::MD5));
	}

	MD5Signature::MD5Signature(const std::string Name, const unsigned int Size, const MD5Array& Value) : m_Name(Name), m_Size(Size), m_Value(Value)
	{
	}

	MD5Signature::~MD5Signature()
	{
	}

	std::string MD5Signature::GetName() const
	{
		return (this->m_Name);
	}

	unsigned int MD5Signature::GetSize() const
	{
		return (this->m_Size);
	}

	const MD5Signature::MD5& MD5Signature::GetValue() const
	{
		return ((MD5Signature::MD5&)*(this->m_Value.data()));
	}

	const MD5Signature::MD5Array& MD5Signature::GetArrayValue() const
	{
		return (this->m_Value);
	}

	void MD5Signature::ConvertBufferToMD5(const std::vector<unsigned char>& Buffer, MD5& Hash)
	{
		if (Buffer.size() != sizeof(MD5))
		{
			throw std::exception("Buffer size is invalid!");
		}
		else
		{
			Hash[0] = *((unsigned int*)&Buffer[0]);
			Hash[1] = *((unsigned int*)&Buffer[4]);
			Hash[2] = *((unsigned int*)&Buffer[8]);
			Hash[3] = *((unsigned int*)&Buffer[12]);
		}
	}

	void MD5Signature::ConvertBufferToMD5(const std::vector<unsigned char>& Buffer, MD5Array& Hash)
	{
		if (Buffer.size() != sizeof(MD5Array))
		{
			throw std::exception("Buffer size is invalid!");
		}
		else
		{
			Hash[0] = *((unsigned int*)&Buffer[0]);
			Hash[1] = *((unsigned int*)&Buffer[4]);
			Hash[2] = *((unsigned int*)&Buffer[8]);
			Hash[3] = *((unsigned int*)&Buffer[12]);
		}
	}
}